package org.ym.database.hibernate.base;

import com.google.gson.JsonObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.transaction.annotation.Transactional;
import org.ym.database.hibernate.query.QueryFilter;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author ym
 */
@Transactional(readOnly = true)
public abstract class BaseRepositoryService<T extends BaseModel,ID,R extends BaseRepository<T,ID>> implements BaseInterface<T,ID> {
    /**
     * 只能按类型注入
     */
    @Autowired
    protected R baseRepository;

    @PersistenceContext
    protected EntityManager entityManager;
    /**
     * 查询所有数据
     * @param queryFilter 查询条件
     * @param classZ 当前类
     * @return 数据
     */
    @Override
    public List<T> queryAll(QueryFilter queryFilter, Class<T> classZ){
        return baseRepository.queryAll(queryFilter,classZ);
    }

    /**
     * 分页查询数据
     * @param queryFilter 查询条件
     * @param classZ 当前类
     * @return 数据
     */
    @Override
    public Page<T> queryPage(QueryFilter queryFilter, Class<T> classZ){
        return baseRepository.queryPage(queryFilter,classZ);
    }

    /**
     * 查询数量
     * @param queryFilter 查询条件
     * @param classZ 当前类型
     * @return 数量
     */
    @Override
    public long count(QueryFilter queryFilter,Class<T> classZ){
        return baseRepository.count(queryFilter,classZ);
    }

    /**
     * 保存数据，不会立刻刷新到数据库，慎用该方法。
     * @param model 对象
     * @return 保存后对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T save(T model){
        return baseRepository.save(model);
    }

    /**
     * 保存并刷新到数据库
     * @param model 对象
     * @return 保存的对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T saveAndFlush(T model){
        return baseRepository.saveAndFlush(model);
    }

    /**
     * 保存所有，不flush
     * @param modelList 数据
     * @return 数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> saveAll(List<T> modelList){
        return baseRepository.saveAll(modelList);
    }

    /**
     * 保存所有,flush数据
     * @param modelList 数据
     * @return 数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> saveAllAndFlush(List<T> modelList){
        return baseRepository.saveAllAndFlush(modelList);
    }

    /**
     * 插入数据
     * @param model 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T insert(T model){
        if(model != null) {
            entityManager.persist(model);
        }
        return model;
    }

    /**
     * 插入数据,并flush
     * @param model 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T insertAndFlush(T model){
        if(model != null) {
            entityManager.persist(model);
            entityManager.flush();
        }
        return model;
    }

    /**
     * 批量插入所有数据,不执行校验
     * @param modelList 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> insertAll(List<T> modelList){
        List<T> result = new ArrayList<>();
        if(modelList != null && modelList.size() > 0) {
            for (T entity : modelList) {
                result.add(insert(entity));
            }
        }
        return result;
    }

    /**
     * 批量插入所有数据,不执行校验,并且flush
     * @param modelList 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> insertAllAndFlush(List<T> modelList){
        List<T> result = new ArrayList<>();
        if(modelList != null && modelList.size() > 0) {
            for (T entity : modelList) {
                result.add(insert(entity));
            }
            entityManager.flush();
        }
        return result;
    }

    /**
     * 更新数据
     * @param model 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T update(T model){
        if(model != null) {
            return entityManager.merge(model);
        }
        return null;
    }

    /**
     * 插入数据,并flush
     * @param model 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public T updateAndFlush(T model){
        T result = null;
        if(model != null) {
            result = entityManager.merge(model);
            entityManager.flush();
        }
        return result;
    }

    /**
     * 批量插入所有数据,不执行校验
     * @param modelList 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> updateAll(List<T> modelList){
        List<T> result = new ArrayList<>();
        if(modelList != null && modelList.size() > 0) {
            for (T entity : modelList) {
                result.add(update(entity));
            }
        }
        return result;
    }

    /**
     * 批量插入所有数据,不执行校验,并且flush
     * @param modelList 新数据
     * @return 保存后数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<T> updateAllAndFlush(List<T> modelList){
        List<T> result = new ArrayList<>();
        if(modelList != null && modelList.size() > 0) {
            for (T entity : modelList) {
                result.add(update(entity));
            }
            entityManager.flush();
        }
        return result;
    }

    /**
     * 根据id获取数据
     * @param id 主键
     * @return 数据
     */
    @Override
    public Optional<T> getById(ID id){
        if(id != null) {
            return baseRepository.findById(id);
        }else {
            return Optional.empty();
        }
    }
    /**
     * 根据idList获取数据
     * @param idList id集合
     * @return 数据
     */
    @Override
    public List<T> getByIds(List<ID> idList){
        if(idList != null && !idList.isEmpty()){
            return baseRepository.findAllById(idList);
        }else{
            return new ArrayList<>();
        }
    }
    /**
     * 根据model集合删除数据
     * @param modelArray model集合数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delByModelList(T[] modelArray){
        if(modelArray != null && modelArray.length > 0) {
            baseRepository.deleteAllInBatch(Arrays.asList(modelArray));
        }
    }
    /**
     * 根据model集合删除数据
     * @param modelList model集合数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delByModelList(List<T> modelList){
        if(modelList != null && !modelList.isEmpty()) {
            baseRepository.deleteAllInBatch(modelList);
        }
    }
    /**
     * 删除数据
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delById(ID id){
        if(id != null) {
            baseRepository.deleteById(id);
        }
    }

    /**
     * 批量删除数据
     * @param idList id集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delByIds(List<ID> idList){
        if(idList != null && !idList.isEmpty()) {
            baseRepository.deleteAllByIdInBatch(idList);
        }
    }

    /**
     * 批量删除数据
     * @param idArray id数组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delByIds(ID[] idArray){
        if(idArray != null && idArray.length > 0) {
            baseRepository.deleteAllByIdInBatch(Arrays.asList(idArray));
        }
    }

    /**
     * 查询所有数据,支持min、max、分组查询等
     * @param queryFilter 查询条件
     * @param classZ 表类
     * @return 数据
     */
    @Override
    public List<Object> query(QueryFilter queryFilter, Class<T> classZ){
        return baseRepository.query(queryFilter,classZ);
    }

    /**
     * 查询所有数据，并把查询结果转换成JsonObject
     * @param queryFilter 查询条件
     * @param classZ 表类
     * @return 数据集
     */
    @Override
    public List<JsonObject> queryAsJsonObject(QueryFilter queryFilter,Class<T> classZ){
        return baseRepository.queryAsJsonObject(queryFilter,classZ);
    }
}
